/**
 * 
 */
package gui.controller;

import engine.Service;
import exception.DempsterTotalConflictException;
import exception.JointNotPossibleException;
import exception.MassDistributionNotValidException;
import exceptions.NullSourcesException;
import gui.view.ResultsPanel;
import gui.view.SimulationPanel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Hashtable;

import javax.swing.JOptionPane;
import javax.swing.table.DefaultTableModel;

import massDistribution.JointMassDistribution;
import massDistribution.MassDistribution;
import stubs.ServiceStub;
import stubs.Simulator;

/**
 * @author Elisa Costante
 * 
 */
public class SimulationPanelListener implements ActionListener {

	private SimulationPanel panel;

	private ArrayList<Service> allCandidateServices = new ArrayList<Service>();
	private Service caller;
	private Hashtable<Service, ArrayList<JointMassDistribution>> allReputationHashMap;
	private Hashtable<Service, ArrayList<MassDistribution>> allAggregateTrust;
	private Hashtable<Service, MassDistribution> allMonitoredMass;

	/**
	 * @param simulationPanel
	 */
	public SimulationPanelListener(SimulationPanel simulationPanel) {
		this.panel = simulationPanel;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equalsIgnoreCase("selectedCaller")) {
			selectedCallerAction();

		} else if (e.getActionCommand().equalsIgnoreCase("selectedCallee")) {
			addCalleeAction();

		} else if (e.getActionCommand().equalsIgnoreCase("removeCallee")) {
			removeCalleeAction();

		} else if (e.getActionCommand().equalsIgnoreCase("runSimulation")) {
			try {
				runSimulationAction();
			} catch (MassDistributionNotValidException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (JointNotPossibleException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (ParameterForSimulationNotValid exception) {
				// TODO Auto-generated catch block
				exception.printStackTrace();
			} catch (CloneNotSupportedException ex) {
				// TODO Auto-generated catch block
				ex.printStackTrace();
			}

		}
	}

	/**
	 * @throws JointNotPossibleException
	 * @throws MassDistributionNotValidException
	 * @throws ParameterForSimulationNotValid
	 * @throws CloneNotSupportedException
	 * 
	 */
	private void runSimulationAction()
			throws MassDistributionNotValidException,
			JointNotPossibleException, ParameterForSimulationNotValid,
			CloneNotSupportedException {
		this.allReputationHashMap = new Hashtable<Service, ArrayList<JointMassDistribution>>();
		this.allAggregateTrust = new Hashtable<Service, ArrayList<MassDistribution>>();
		this.allMonitoredMass = new Hashtable<Service, MassDistribution>();

		if (allCandidateServices != null && allCandidateServices.size() > 0) {
			simulate();
		} else {
			JOptionPane.showMessageDialog(panel,
					"You should select at least one callee");
		}

	}

	/**
	 * @throws ParameterForSimulationNotValid
	 * @throws JointNotPossibleException
	 * @throws MassDistributionNotValidException
	 * @throws CloneNotSupportedException
	 * 
	 */
	private void simulate() throws ParameterForSimulationNotValid,
			MassDistributionNotValidException, JointNotPossibleException,
			CloneNotSupportedException {

		Simulator simulator = new Simulator();
		// Set up the simulator
		simulator.setAllSources(panel.getFrame().getSourceList());
		simulator.setFrameOfDiscernment(panel.getFrame()
				.getFrameOfDiscernment());
		simulator
				.setTrustConfiguration(panel.getFrame().getClassAttributeMap());
		simulator.setMonitoredServices(panel.getFrame().getMonitoredServices());

		if (simulator.isVAlid()) {

			for (Service candidateService : allCandidateServices) {

				// Compute the Reputation for each candidate service
				ArrayList<JointMassDistribution> allReputationMass = null;
				try {
					allReputationMass = simulator
							.getAlltheReputations((Service) candidateService
									.clone());
				} catch (NullSourcesException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				allReputationHashMap.put(candidateService, allReputationMass);

				// compute the relatioship mass
				MassDistribution relationshiptrust = simulator.getRelationship(
						(Service) caller.clone(), (Service) candidateService
								.clone());
				allMonitoredMass.put(candidateService, relationshiptrust);

				// compute the aggregate trust
				ArrayList<MassDistribution> allAggregateMass = new ArrayList<MassDistribution>();
				for (int i = 0; i < allReputationMass.size(); i++) {
					MassDistribution reputation = allReputationMass.get(i);

					MassDistribution aggregateTrust;
					try {
						aggregateTrust = simulator.getAggregateTrust(
								reputation, relationshiptrust);
						allAggregateMass.add(aggregateTrust);
					} catch (DempsterTotalConflictException e) {
						e.printStackTrace();
						// In the case where Dempster joint is not applicable
						// add
						// a mass where all the knowledge is associated to the
						// empty set

					}

				}
				allAggregateTrust.put(candidateService, allAggregateMass);
			}

			// show the Result Panel
			showResultPanel();

		} else {
			throw new ParameterForSimulationNotValid();
		}

	}

	/**
	 * 
	 */
	private void showResultPanel() {
		ResultsPanel resultPanel = new ResultsPanel(allReputationHashMap);
		resultPanel.setAllCandidateServices(allCandidateServices);
		resultPanel.setCallerService(caller);
		resultPanel.setAllAggregateTrustHashMap(allAggregateTrust);
		resultPanel.setFrameOfDiscernment(panel.getFrame()
				.getFrameOfDiscernment());
		resultPanel.setMonitoredMass(allMonitoredMass);
		resultPanel.initPanel();

		// set The result panel
		panel.getFrame().setResultsPanel(resultPanel);
	}

	/**
	 * 
	 */
	private void removeCalleeAction() {
		int row = panel.getAllCalleTable().getSelectedRow();
		if (row >= 0) {
			DefaultTableModel tableModel = panel.getAllCalleTableModel();
			String calleeName = (String) tableModel.getValueAt(row, 0);
			tableModel.removeRow(row);
			allCandidateServices.remove(new ServiceStub(calleeName));
		}

	}

	/**
	 * 
	 */
	private void addCalleeAction() {
		String calleeName = (String) panel.getCalleeComboBox()
				.getSelectedItem();
		Service callee = panel.getFrame().getMonitoredServiceFromName(
				calleeName);
		if (callee != null
				&& !callee.getIdentifierName().equalsIgnoreCase(
						caller.getIdentifierName())) {
			if (!allCandidateServices.contains(callee)) {
				DefaultTableModel tableModel = panel.getAllCalleTableModel();
				tableModel.addRow(new String[] { calleeName });
				try {
					allCandidateServices.add((ServiceStub) callee.clone());
				} catch (CloneNotSupportedException e) {
					e.printStackTrace();
				}

			}
		} else {
			JOptionPane.showMessageDialog(panel,
					"You cannot add a caller as callee.");
		}

	}

	/**
	 * 
	 */
	private void selectedCallerAction() {
		String callerName = (String) panel.getCallerComboBox()
				.getSelectedItem();
		if (callerName != null
				&& panel.getFrame().getMonitoredServices() != null) {
			caller = panel.getFrame().getMonitoredServiceFromName(callerName);
			try {
				caller = (ServiceStub) caller.clone();
			} catch (CloneNotSupportedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}
